package com.hhck.utils;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;

@Component
public class UploadFileUtil {

    // @Value注解无法给静态变量注入，因为@Value是在bean实例化后，在属性填充过程中进行赋值的，static初始化要早于@value
    private static String uploadPath;

    // 可以将@Value放到静态变量的set方法上面完成注入，注意：set方法去掉static
    @Value("${file.upload-path}")
    public void setUploadPath(String uploadPath) {
        UploadFileUtil.uploadPath = uploadPath;
    }

    private static String appName;

    @Value("${spring.application.name}")
    public void setAppName(String appName) {
        UploadFileUtil.appName = appName;
    }

    /**
     * 上传文件到target目录（类路径下）
     *   用于生产环境，不会因为系统迁移而丢失数据
     */
    public static Boolean uploadFileToTarget(MultipartFile file, String fileOriginalFilename) {

        try {
            // uploadPath保存的是类路径 -- classpath:static/img/upload
            // 上传文件不能使用类路径，需要使用磁盘路径（绝对路径）

            // 1、获取磁盘文件目录：通过类路径获取 -- C:\HengHeCangKu\hhck-server\target\classes\static\img\ upload
            File uploadPathDir = ResourceUtils.getFile(uploadPath);

            // 2、获取磁盘路径：通过磁盘文件目录获取 -- C:\HengHeCangKu\hhck-server\target\classes\static\img\ upload
            String uploadFileAbsolutePath = uploadPathDir.getAbsolutePath();

            // 3、拼接文件名
            String uploadFilePath = uploadFileAbsolutePath + "\\" + fileOriginalFilename;

            // 4、文件上传
            file.transferTo(new File(uploadFilePath));

            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 上传文件到resources目录下（静态资源包下）
     *   用于开发测试环境（同时也需要上传到target目录下），防止系统迁移而丢失数据
     */
    public static Boolean uploadFileToResources(MultipartFile file, String fileOriginalFilename) {

        try {
            // 1、获取项目工作目录 -- 例如：C:\HengHeCangKu
            String projectDir = System.getProperty("user.dir");

            // 2、拼接应用名和静态资源路径
            String staticResourcePath = projectDir + "\\" + appName + "\\src\\main\\resources\\static\\img\\upload";

            // 3、拼接文件名
            String uploadFileToResourcesPath = staticResourcePath + "\\" + fileOriginalFilename;

            // 4、文件上传
            file.transferTo(new File(uploadFileToResourcesPath));

            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将文件同时上传到 target 和 resources 目录下
     *   用于开发测试环境，防止系统迁移而丢失数据
     */
    public static Boolean uploadFile(MultipartFile file, String fileOriginalFilename) {

        // 1、拷贝上传的文件（前端传递的文件存放在临时目录，使用完后会自动删除，所以需要拷贝一份进行二次使用）
        MultipartFile copyFile = UploadFileUtil.fileCopy(file);

        // 2、上传到target目录下（先使用原临时文件）
        boolean target = UploadFileUtil.uploadFileToTarget(file, fileOriginalFilename);

        // 3、上传到resources目录下（上面文件上传完成后临时文件自动删除，所以这里要使用拷贝的文件进行上传）
        boolean resources = UploadFileUtil.uploadFileToResources(copyFile, fileOriginalFilename);

        if (target && resources) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 拷贝MultipartFile文件
     */
    public static MultipartFile fileCopy(MultipartFile file) {

        try {
            // 获取文件的字节输入流
            InputStream inputStream = file.getInputStream();

            // 创建字节输出流
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

            // 拷贝文件内容
            FileCopyUtils.copy(inputStream, byteArrayOutputStream);

            // 复制写入的文件
            InputStream outputToInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            MultipartFile copyFile = new MockMultipartFile(file.getName(), outputToInputStream);

            // 关闭流
            inputStream.close();
            byteArrayOutputStream.close();
            outputToInputStream.close();

            // 返回复制的文件
            return copyFile;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}

